import asyncio
import json
import os
import pandas as pd
import requests
import base64
import re

from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponseBadRequest, JsonResponse, HttpResponseNotAllowed, FileResponse, Http404, \
    StreamingHttpResponse
from openai import OpenAI

client = OpenAI(
    api_key="sk-064abae05a144789b9d1e5aebae9f567",  # 配置API-KEY
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",  # 可修改相关url
)

all_url = "192.168.1.101"
# all_url = "172.20.0.89"

def chat_llm(prompt: str, system: str) -> json:
    """
    聊天大模型对话
    """
    completion = client.chat.completions.create(
        # 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
        model="qwen3-32b",
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": prompt},
        ],
        # Qwen3模型通过enable_thinking参数控制思考过程（开源版默认True，商业版默认False）
        # 使用Qwen3开源版模型时，若未启用流式输出，请将下行取消注释，否则会报错
        extra_body={"enable_thinking": False},
    )
    print(completion.model_dump_json())
    return completion.model_dump_json()

def chat_llm_stream(prompt: str, system: str) -> json:
    """
    聊天大模型对话
    """
    completion = client.chat.completions.create(
        # 模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
        model="qwen3-32b",
        messages=[
            {"role": "system", "content": system},
            {"role": "user", "content": prompt},
        ],
        stream=True,  # 启用流式输出
        # Qwen3模型通过enable_thinking参数控制思考过程（开源版默认True，商业版默认False）
        # 使用Qwen3开源版模型时，若未启用流式输出，请将下行取消注释，否则会报错
        extra_body={"enable_thinking": False},
    )

    for chunk in completion:
        if chunk.choices[0].delta.content is not None:
            yield chunk.choices[0].delta.content

def vl_llm(image_url: str):
    """
    视觉大模型对话
    """
    system = """你是一位具备专业心理学背景的图像分析专家，能够基于输入图片内容综合判断人物的心理状态。请从以下三个方面对图片进行全面分析：

    1. 图片内容识别（content_detection）：识别图片中包含的人物、物体、环境等要素；
    2. 心理状态检测（safety_check）：判断图片是否包含反映负面情绪、心理异常或其他潜在风险因素；
    3. 心理质量分析（quality_analysis）：评估图片的清晰度、色彩、构图等是否传递出积极或消极的心理特征。
    
请以 JSON 格式返回结果，每一项应包含：

    - type: 分析类别标识（如 content_detection）
    - title: 中文标题（如“图片内容识别”）
    - content: 分析描述
    - risk_level: 风险等级（low / medium / high）
    
【输出格式】：

    '''json
    [
        {
            "type": "content_detection",
            "title": "图片内容识别",
            "content": "图像中识别出人物形象、环境建筑及文字信息，具备一定的社交与情境特征，有助于开展心理意义分析。",
            "risk_level": "low"
        },
        {
            "type": "safety_check",
            "title": "心理状态检测",
            "content": "图像未出现明显的负面情绪表达（如悲伤、愤怒、压抑），人物面部表情自然，体态放松，未检测到心理风险信号。",
            "risk_level": "low"
        },
        {
            "type": "quality_analysis",
            "title": "心理质量分析",
            "content": "图像构图协调、色彩温和，画面传递出积极的情绪基调，反映出相对稳定、健康的心理状态。",
            "risk_level": "low"
        }
    ]
    '''
"""
    completion = client.chat.completions.create(
        model="qwen-vl-max",

        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "image_url",
                        "image_url":{"url": image_url}
                    },
                ]
            },
            {
                "role": "system",
                "content": system
            }
        ]
    )
    data = json.loads(completion.model_dump_json())["choices"][0]["message"]["content"]
    return_data = json_extract(data)
    return {"infos": return_data}


def json_extract(json_datas: str):
    """
    从结果中提取json
    """
    # 用正则匹配代码块里的内容（假设只有一个json块）
    pattern = r"```json\n(.*?)\n```"

    match = re.search(pattern, json_datas, re.DOTALL)
    if match:
        json_str = match.group(1)  # 提取JSON字符串
        try:
            data = json.loads(json_str)
            return data
        except json.JSONDecodeError as e:
            print("JSON解析错误:", e)
    else:
        print("未找到匹配的JSON代码块")


def save_report(all_score: int, score_all: list, dimensions, question):
    url = f"http://{all_url}:8001/get_doc"
    data1 = {
        "data": {
            "all_score": all_score,
            "score_all": score_all,
            "dimensions": dimensions,
            "eval": question["eval"]
        }
    }

    response = requests.post(url, json=data1)
    # 检查是否成功并保存返回的 Word 文件
    if response.status_code == 200:
        with open("./static/reports/downloaded_report.docx", "wb") as f:
            f.write(response.content)
        print("Word 文档已保存为 downloaded_report.docx")
    else:
        print("请求失败：", response.status_code)


def encode_url(img_byte: bytes) -> str:
    """
    转化成api所需要的格式
    """
    # 将图片 bytes 编码为 base64
    encoded_image = base64.b64encode(img_byte).decode('utf-8')

    # 构造 data URL（假设为 jpeg，可以根据上传内容调整为 png 等）
    data_url = f"data:image/jpeg;base64,{encoded_image}"
    return data_url

@login_required(login_url="/login")
def picture(request):
    if request.method == "POST":
        uploaded_file = request.FILES.get('image')
        if not uploaded_file:
            return JsonResponse({'error': 'No file uploaded'}, status=400)


        # 将文件读取为 bytes（二进制）
        img_bytes = uploaded_file.read()
        data_url = encode_url(img_bytes)
        data = vl_llm(data_url)["infos"]
        return JsonResponse(
            {
                'success': True,
                'results':data
            },
            status=200)
    return render(request, "picture.html")

@login_required(login_url="/login")
def get_ghq_questions(request):
    if request.method == "POST":
        body_unicode = request.body.decode('utf-8')
        data = json.loads(body_unicode)
        question_name = data.get("name", "")
        # 假设 questions.json 存在于当前 根目录的static下的question
        file_path = os.path.join(settings.BASE_DIR, "static", "question", "question_data.json")

        with open(file_path, "r", encoding='utf-8') as f:
            questions = json.load(f)
        for question in questions:

            if question_name == question["title"]:
                return JsonResponse(question["questions"], safe=False)


    # ✅ 增加这句以防 GET 或其他非法方法导致报错
    return HttpResponseNotAllowed(['POST'])

@login_required(login_url="/login")
def question(request):
    if request.method == "POST":
        pass
    return render(request, 'question.html')

@login_required(login_url="/login")
def question_completed(request):
    return render(request, 'completed.html')

@login_required(login_url="/login")
async def question1(request):
    all_score = 0
    # 记录每一题的得分
    score_all = []
    # 维度记录
    dimensions = []
    if request.method == 'POST':
        try:
            body_unicode = request.body.decode('utf-8')
            data = json.loads(body_unicode)

            title = data.get("name", "")
            answers = data.get("answers", [])
            question_first = data.get("message", None)

            if not answers:
                return JsonResponse({"error": "没有 answers 数据"}, status=400)
            file_path = os.path.join(settings.BASE_DIR, "static", "question", "question_score.json")
            with open(file_path, "r", encoding='utf-8') as f:
                question_scores = json.load(f)["questionnaires"]
            for question in question_scores:
                if question["title"] == title:
                    eval_data = question["eval"]
                    first = question["score"][0]
                    second = question["score"][1]
                    third = question["score"][2]
                    for answer in answers:
                        if answer["answer"] == 0:
                            all_score += first
                            score_all.append(first)
                        elif answer["answer"]  == 1:
                            all_score += second
                            score_all.append(second)
                        elif answer["answer"]  == 2:
                            all_score += third
                            score_all.append(third)
                    dimension_datas = question["dimensions"]
                    for dimension in dimension_datas:
                        name = dimension["name"]
                        lists = dimension["list"]
                        score = 0
                        for list in lists:
                            choice = answers[list - 1]["answer"]
                            if choice == 0:
                                score += first
                            elif choice == 1:
                                score += second
                            elif choice == 2:
                                score += third

                        item = {
                            "name": name,
                            "score": score
                        }
                        dimensions.append(item)

                    save_report(all_score, score_all, dimensions, question)


            system_prompt = """您是一个心理学专家，请根据评测维度、评分解释、相关建议以及结合用户分数、用户问题来对用户心理状况进行分析，并给用户给予心理安慰以及这些心理状况产生的原因和相关的解决办法。请多生成一些相关的、好看的图标而非图片，最终所有文字全部以Markdown格式生成输出。"""
            dimension_texts = "".join([f"    {d['name']}: {d['score']}" for d in dimensions])
            eval_texts = "".join([f"    {e['name']}：{e['text']}" for e in eval_data])
            help_texts = "".join([f"    {e['help']}" for e in eval_data])
            prompt = f"""用户问题：{question_first}
                    
【测评维度与用户分数】
{dimension_texts}
    
【评分解释】
    {eval_texts}

【相关建议】
    {help_texts}
"""

            async def generate_stream_response():
                try:
                    for chunk in chat_llm_stream(prompt, system_prompt):

                        yield f"data: {json.dumps({'content': chunk})}\n\n"
                        await asyncio.sleep(0.01)
                except Exception as e:
                    print(e)
                    yield f"data: {json.dumps({'content': str(e)})}\n\n"
            response = StreamingHttpResponse(
                generate_stream_response(),
                content_type='text/event-stream'
            )
            return response

        except Exception as e:
            print(e)
            return JsonResponse({"error": "服务器处理失败", "details": str(e)}, status=500)

    return JsonResponse({"error": "仅支持 POST"}, status=405)

@login_required(login_url="/login")
def download_report(request):
    file_path = os.path.join(settings.BASE_DIR, "static", 'reports', "downloaded_report.docx")
    if not os.path.exists(file_path):
        print("文件不存在")
        raise Http404("报告文件不存在")

    response = FileResponse(open(file_path, 'rb'), as_attachment=True, filename="report.docx")
    return response
